package personnel.department.pages.addpage;

import static java.util.Collections.emptySet;
import static personnel.department.dao.HibernateUtils.getDAO;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;

import personnel.department.dao.entity.Career;
import personnel.department.dao.entity.Diplom;
import personnel.department.dao.entity.Education;
import personnel.department.dao.entity.Employee;
import personnel.department.dao.entity.EmployeeType;
import personnel.department.dao.entity.Pasport;
import personnel.department.dao.entity.PersonalData;
import personnel.department.dao.entity.RecordService;
import personnel.department.dao.entity.StructualSubdivision;
import personnel.department.pages.PagesLogic;
import personnel.department.pages.TwoColumnFieldsComposite;
import personnel.department.pages.constants.Icons;
import personnel.department.pages.widgets.AbstractWidget;
import personnel.department.pages.widgets.combo.AbstractComboWidget;
import personnel.department.utils.TranslatorUtils;

import com.google.common.collect.Maps;

public class AddPersonalPage {

	private static final String EDIT_PERSON = "Редактировать работника";

	private static final String ADD_PERSON = "Добавить работника";

	private TwoColumnFieldsComposite overviewEditor;

	private AdoptedToStructuralEditor adoptedToStructuralEditor;
	private TranslationEditor translationEditor;
	private ValidationEditor validationEditor;
	private RetrainingEditor retrainingEditor;
	private QuitEditor quitEditor;
	private DegreeEditor degreeEditor;
	private QualificationEditor qualificationEditor;
	private CertificatesEditor certificatesEditor;
	private InternshipEditor internshipEditor;
	private Employee employee;
	private CTabFolder tabFolder;

	private String pageName;

	private PagesLogic pageLogic;

	private CTabItem tabItem;

	public AddPersonalPage() {
		this(null);
	}

	public AddPersonalPage(Employee employee) {
		this.employee = employee;
		pageLogic = PagesLogic.getInstance();
		tabFolder = pageLogic.getTabFolder();
	}

	public void createContent() {
		pageName = employee == null ? ADD_PERSON : EDIT_PERSON;
		if (isPageExist()) {
			return;
		}
		tabItem = pageLogic.createTabItem(pageName);
		Composite parent = new Composite(tabFolder, SWT.NONE);
		parent.setLayout(new GridLayout());
		parent.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());

		createSavePanel(parent);

		createTabEditors(parent);
		tabItem.setControl(parent);
		tabFolder.setSelection(tabItem);
	}

	private boolean isPageExist() {
		for (CTabItem item : tabFolder.getItems()) {
			if (item.getText().equals(pageName)) {
				tabFolder.setSelection(item);
				if (pageName.equals(EDIT_PERSON)) {
					item.dispose();
					return false;
				}
				return true;
			}
		}
		return false;
	}

	private void createTabEditors(Composite parent) {
		CTabFolder tabFolder = createTabFolder(parent);
		createOverviewTab(tabFolder);

		createCertificateTab(tabFolder);
		createQualificationTab(tabFolder);
		createAdoptedTStructuralTab(tabFolder);
		createDegreeTab(tabFolder);
		createQuitTab(tabFolder);
		createRetrainingTab(tabFolder);
		createTranslationTab(tabFolder);
		createValidationTab(tabFolder);
		createInternshipTab(tabFolder);
		tabFolder.setSelection(0);
	}

	private void createInternshipTab(CTabFolder tabFolder) {
		internshipEditor = new InternshipEditor(tabFolder, 
				employee != null ? employee.getEducation().getInternship() : emptySet());
		internshipEditor.createContent();
	}

	private void createSavePanel(Composite parent) {
//		Composite savePanel = new Composite(parent, SWT.NONE);
//		savePanel.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
//		savePanel.setLayout(new GridLayout());
		Button saveButton = new Button(parent, SWT.NONE);
		saveButton.setImage(new Image(saveButton.getDisplay(), Icons.SAVE_ALL_ICON.getPath()));
		saveButton.setText("Сохранить все");
//		GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.CENTER).grab(true, false).span(15, 5).applyTo(saveButton);
		saveButton.addListener(SWT.Selection, new Listener() {

			//TODO REFACT ME!!!
			@Override
			public void handleEvent(Event arg0) {
				boolean newEmployee = true;
				if (employee == null) {
					employee = new Employee();
					newEmployee = false;
				}
				List<Object> overviewParams = TranslatorUtils.getParamsByWidgets(overviewEditor.getWidgetByName());
				try {
					employee.setSurname((String) overviewParams.get(0));
					employee.setFirstName((String) overviewParams.get(1));
					employee.setSecondName((String) overviewParams.get(2));
					employee.setNotes((String) overviewParams.get(3));

					Diplom medicDiplom = new Diplom();
					medicDiplom.setFaculty((String) overviewParams.get(4));
					medicDiplom.setSeries((Integer)overviewParams.get(5));
					medicDiplom.setDiplomNumber((Integer)overviewParams.get(6));
					medicDiplom.setStartEducation((Date)overviewParams.get(7));
					medicDiplom.setFinishEducation((Date)overviewParams.get(8));
					medicDiplom.setMedicDiplom(true);

					employee.setSubdivision(new StructualSubdivision((String) overviewParams.get(9)));

					PersonalData personalData = new PersonalData();
					personalData.setInn((Long)overviewParams.get(10));
					personalData.setSnils((Long)overviewParams.get(11));

					personalData.setMedicPolic((Long)overviewParams.get(12));

					Pasport pasport = new Pasport();
					pasport.setSeries((Integer)overviewParams.get(13));
					pasport.setNumberPasport((Integer)overviewParams.get(14));
					pasport.setIssuedBy((String)overviewParams.get(15));
					pasport.setDateIssued((Date)overviewParams.get(16));
					personalData.setPasport(pasport);

					RecordService recordService = new RecordService();
					recordService.setSeries((String)overviewParams.get(17));
					recordService.setNumberRecordService((String)overviewParams.get(18));
					personalData.setRecordService(recordService);

					EmployeeType employeeType = new EmployeeType();
					employeeType.setPost((String)overviewParams.get(20));
					employeeType.setType((String)overviewParams.get(19));
					employee.setType(employeeType);

					employee.setPersonalData(personalData);

					Education education = new Education();
					education.setMedicDiplom(medicDiplom);
					employee.setEducation(education);
					//				getDAO().add(employee);


					education.setCertificates(certificatesEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					education.setDegrees(degreeEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					education.setInternship(internshipEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					education.setQualifications(qualificationEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					education.setRetrainings(retrainingEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					education.setValidations(validationEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					Career career = new Career();

					career.setAdoptedToStructural(adoptedToStructuralEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					career.setQuits(quitEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					career.setTranslations(translationEditor.getAllInstances().stream()
							.peek((object) -> object.setEmployee(employee))
							.collect(Collectors.toSet()));

					employee.setCareer(career);
				} catch (Exception e) {
					MessageDialog.openError(pageLogic.getMainShell(), "Ошибка при сохранении", "Не все поля заданы!");
					return;
				}
//				try {
					getDAO().add(employee);
//				} catch (Exception e) {
//					MessageDialog.openError(pageLogic.getMainShell(), "Ошибка при сохранении", "Ошибка при сохранении!");
//					return;
//				}

				String message = newEmployee ? "Сотрудник успешно добавлен" : "Сотрудник успешно изменен";
				MessageDialog.openInformation(pageLogic.getMainShell(), "Сохранение данных", message);
				if (newEmployee) {
					tabItem.dispose();
					return;
				}
				certificatesEditor.resetWidget();
				degreeEditor.resetWidget();
				internshipEditor.resetWidget();
				qualificationEditor.resetWidget();
				retrainingEditor.resetWidget();
				validationEditor.resetWidget();
				adoptedToStructuralEditor.resetWidget();
				quitEditor.resetWidget();
				translationEditor.resetWidget();
				overviewEditor.getWidgetByName().stream()
				.map(pair -> pair.getRight())
				.forEach(w -> w.reset());
				certificatesEditor.getTable().clear();
				degreeEditor.getTable().clear();
				internshipEditor.getTable().clear();
				qualificationEditor.getTable().clear();
				retrainingEditor.getTable().clear();
				validationEditor.getTable().clear();
				adoptedToStructuralEditor.getTable().clear();
				quitEditor.getTable().clear();
				translationEditor.getTable().clear();

			}
		});
	}

	private void createAdoptedTStructuralTab(CTabFolder tabFolder) {
		adoptedToStructuralEditor = new AdoptedToStructuralEditor(tabFolder, 
				employee != null ? employee.getCareer().getAdoptedToStructural() : emptySet());
		adoptedToStructuralEditor.createContent();
	}

	private void createTranslationTab(CTabFolder tabFolder) {
		translationEditor = new TranslationEditor(tabFolder, 
				employee != null ? employee.getCareer().getTranslations() : emptySet());
		translationEditor.createContent();
	}

	private void createValidationTab(CTabFolder tabFolder) {
		validationEditor = new ValidationEditor(tabFolder, 
				employee != null ? employee.getEducation().getValidations() : emptySet());
		validationEditor.createContent();
	}

	private void createRetrainingTab(CTabFolder tabFolder) {
		retrainingEditor = new RetrainingEditor(tabFolder, 
				employee != null ? employee.getEducation().getRetrainings() : emptySet());
		retrainingEditor.createContent();
	}

	private void createQuitTab(CTabFolder tabFolder) {
		quitEditor = new QuitEditor(tabFolder, 
				employee != null ? employee.getCareer().getQuits() : emptySet());
		quitEditor.createContent();
	}

	private void createDegreeTab(CTabFolder tabFolder) {
		degreeEditor = new DegreeEditor(tabFolder, 
				employee != null ? employee.getEducation().getDegrees() : emptySet());
		degreeEditor.createContent();
	}


	private void createQualificationTab(CTabFolder tabFolder) {
		qualificationEditor = new QualificationEditor(tabFolder, 
				employee != null ? employee.getEducation().getQualifications() : emptySet());
		qualificationEditor.createContent();
	}

	private void createCertificateTab(CTabFolder tabFolder) {
		certificatesEditor = new CertificatesEditor(tabFolder, 
				employee != null ? employee.getEducation().getCertificates() : emptySet());
		certificatesEditor.createContent();
	}


	private void createOverviewTab(CTabFolder tabFolder) {
		List<Field> overviewFields = getOverviewFields();
		CTabItem overviewitem = new CTabItem(tabFolder, SWT.NONE);
		overviewitem.setText("Основные данные");

		overviewEditor = new TwoColumnFieldsComposite(tabFolder, overviewFields ,SWT.NONE);
		overviewEditor.createControl();
		List<Pair<String,AbstractWidget<?>>> widgetByName = overviewEditor.getWidgetByName();
		AbstractComboWidget typeCombo = getComboWidget(widgetByName, "type");
		AbstractComboWidget postCombo = getComboWidget(widgetByName, "post");
		postCombo.setEnabled(employee != null);

		typeCombo.addSelectionAction(event -> {
			String type = typeCombo.getValue();
			if (StringUtils.isEmpty(type)) {
				postCombo.setEnabled(false);
				return;
			}
			Map<String, Object> params = Maps.newHashMap();
			params.put("type", type);
			postCombo.setItems("SELECT DISTINCT et.post FROM EmployeeType et WHERE et.type = :type", params);
			postCombo.setEnabled(true);
		});


		typeCombo.getValue();

		if (employee != null) {
			initEditors();
		}

		overviewitem.setControl(overviewEditor);
	}

	private AbstractComboWidget getComboWidget(
			List<Pair<String, AbstractWidget<?>>> widgetByName, String fieldName) {
		AbstractComboWidget typeCombo = (AbstractComboWidget) widgetByName.stream()
				.map(pair -> pair.getRight())
				.filter(widget -> widget.getFieldName().equals(fieldName) && widget.getFieldType().equals(EmployeeType.class))
				.findAny()
				.get();
		return typeCombo;
	}

	@SuppressWarnings("unchecked")
	private void initEditors() {
		for (Pair<String, AbstractWidget<?>> pair : overviewEditor.getWidgetByName()) {
			try {
				pair.getRight().setValueByObject(employee, Education.class, Career.class);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private CTabFolder createTabFolder(Composite parent) {
		CTabFolder tabFolder = new CTabFolder(parent, SWT.BOTTOM);
		tabFolder.setSimple(false);
		GridDataFactory.fillDefaults().grab(true, true).applyTo(tabFolder);
		tabFolder.setLayout(new GridLayout());
		tabFolder.setBackground(pageLogic.getMainShell().getBackground());
		return tabFolder;
	}

	private List<Field> getOverviewFields() {
		Field[] fields = Employee.class.getDeclaredFields();
		Field[] medicDeplomFields = Diplom.class.getDeclaredFields();
		return TranslatorUtils.getTranslatorFields(ArrayUtils.addAll(fields, medicDeplomFields), Education.class, Career.class);
	}

}
